<?php

namespace Common\Middleware\Sign;


use Common\Exception\BaseException;
use Common\Helpers\DebugHelper;
use Common\Models\sys\SysProject;
use Common\Services\AuthServer;
use Common\Sign\CodeConst;
use Common\Sign\SignException;
use Common\WebSocket\Utility\VerifyProject;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
use Hyperf\HttpServer\Router\Dispatched;
use Hyperf\WebSocketServer\Context as WebSocketContext;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\SimpleCache\CacheInterface;
use Psr\SimpleCache\InvalidArgumentException;
use Swoole\Exception;


class SignMiddleware implements MiddlewareInterface
{

    protected ContainerInterface $container;

    protected RequestInterface $request;

    protected HttpResponse $response;

    /**
     * @Inject
     * @var CacheInterface
     */
    #[Inject]
    protected CacheInterface $cache;

    public function __construct(ContainerInterface $container, HttpResponse $response, RequestInterface $request)
    {
        $this->container = $container;
        $this->response = $response;
        $this->request = $request;
    }


    /**
     */
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        try {

            if (!$request->getAttribute('signOptional')){
                return $handler->handle($request);
            }

            /**
             * 获取请求的域名
             */
            $referer =$request->getHeaderLine('referer');
            $domain = parse_url($referer);
            $token = $request->getHeaderLine('access-token');
            $project_sn = $this->request->route('project_sn');
            $Args = $this->request->getParsedBody();

            DebugHelper::consoleWrite('项目权限校验-sign',[
                $request->getHeaders(),
                'project_sn'=>$project_sn,
                'domain'=>$domain,
                'app_id' => $Args
            ]);
            $AuthServer = new AuthServer();
            $project = $AuthServer->checkProjectAppID($project_sn,$domain['host']??'',$Args['app_id']);
            DebugHelper::consoleWrite('项目权限校验完成',[
                'project'=>$project,
                'token'=>$token,
                'project_sn'=>$project_sn,
                'domain'=>$domain
            ]);
            if ($project['code'] !== 200){
                return $this->response->json($project);
            }

            $checkSign = VerifyProject::verifySign($Args);
            DebugHelper::consoleWrite('验证内容反馈', [
               'checkSign' => $checkSign,
               'Args' => $Args,
            ]);

            if ($checkSign['code'] === (int)CodeConst::CODE_90011) {
                DebugHelper::consoleWrite('验证完成');
                $project_id = $this->cache->get($Args['app_id']);
                if (empty($project_id)) {
                    $project_id = $project['id'];
                    $this->cache->set($Args['app_id'], $project_id);
                }
                $request = $request->withAttribute('project_id', $project_id);
                return $handler->handle($request);
            } else {
                return $this->response->json(
                     [
                        'code' => 405,
                        'message' => $checkSign['message'],
                        'data' => $checkSign
                    ]
                );
            }
        } catch (\ErrorException $e) {
            /**
             * 获取当前请求地址
             */
            $request = $request->getAttribute(Dispatched::class)->handler->callback;
            DebugHelper::consoleWrite('签名验证异常-ErrorException', [
                'err' => $e->getMessage(),
                'line' => $e->getLine(),
                'file' => $e->getFile(),
                'request'=> $request,
            ]);
            throw new BaseException(401, $e->getMessage());
        } catch (InvalidArgumentException $e) {
            DebugHelper::consoleWrite('签名验证异常-InvalidArgumentException', [
                'err' => $e->getMessage(),
                'line' => $e->getLine(),
                'file' => $e->getFile()
            ]);
            throw new BaseException(401, $e->getMessage());
        }catch (SignException $e){
            DebugHelper::consoleWrite('签名验证异常-SignException', [
                'err' => $e->getMessage(),
                'line' => $e->getLine(),
                'file' => $e->getFile()
            ]);
            throw new BaseException(401, $e->getMessage());
        }
    }
}